#include <string.h>
#include <event.h>
#include <event2/listener.h>

#include <eventpp/tcp_handler.h>
#include <eventpp/tcp_connection.h>
#include <eventpp/net_base.h>

#include <eventpp/tcp_acceptor.h>
using namespace eventpp;

tcp_acceptor::tcp_acceptor( net_base & base, tcp_acceptor_config * config, tcp_handler * handler )
: base_(base)
, config_(config)
, handler_(handler)
, listener_(NULL)
{
}

eventpp::tcp_acceptor::~tcp_acceptor()
{
	close();
}

void eventpp::tcp_acceptor::close()
{
	if ( listener_ != NULL ) {
		evconnlistener_free( listener_ );
		listener_ = NULL;
	}
}

void eventpp::tcp_acceptor::start()
{
	sockaddr_in sin;
	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(config_->port);
	sin.sin_addr.s_addr = config_->ip;

	listener_ = evconnlistener_new_bind( base_.base(), tcp_acceptor::acceptcb, this, 
		LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 1024, (struct sockaddr *)&sin, sizeof(sin));

}

void eventpp::tcp_acceptor_config::reset()
{
	ip = 0;
	port = 0;
}

void tcp_acceptor::acceptcb(evconnlistener *serv, int sock, sockaddr *sa, int sa_len, void *arg)
{
  tcp_acceptor * acceptor = reinterpret_cast<tcp_acceptor *>(arg);

  tcp_connection * connection = new tcp_connection( acceptor->base_, acceptor->handler_ );
  if( connection->on_accepted(sock, sa, sa_len ) != 0 ) {
    delete connection;
    evutil_closesocket(sock);	
  }
}

